#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <cstring>
#include "Gelaende.h"

/** Erstellen des Gelaendes **/
Gelaende::Gelaende(string* path, int start, int detail)
{
	gelaendeOBJ = osgDB::readNodeFile( path[start] );
	stein1OBJ = osgDB::readNodeFile( path[start+1] );
	stein2OBJ = osgDB::readNodeFile( path[start+2] );
	stein3OBJ = osgDB::readNodeFile( path[start+3] );
	stein4OBJ = osgDB::readNodeFile( path[start+4] );
	schilfOBJ = osgDB::readNodeFile( path[start+5] );

	gelaendeGrp = new Group;
    gelaendeGrp->addChild( gelaendeOBJ.get() );
	steineZusammenstellen();
	if(detail !=0)
		schilfZusammenstellen( &path[start+6], detail );
}

/** Setzen von Steinen **/
void Gelaende::steineZusammenstellen()
{
	/** Stein 1 positionieren **/
	ref_ptr<PositionAttitudeTransform> stein1Scale = scaleObject( stein3OBJ.get(), Vec3( 5.0, 5.0, 5.0 ) );

	ref_ptr<MatrixTransform> steinpos1trans = translateObject( stein1Scale.get(), Vec3( -128.0, -83.0, 40.0 ) );

	gelaendeGrp->addChild( steinpos1trans.get() );

	/** Stein 2 positionieren **/
	ref_ptr<PositionAttitudeTransform> stein2Scale = scaleObject( stein1OBJ.get(), Vec3( 2.0, 2.0, 2.0 ) );

	ref_ptr<MatrixTransform> steinpos2trans = translateObject( stein2Scale.get(), Vec3( -90.0, -80.0, 25.0 ) );

	gelaendeGrp->addChild( steinpos2trans.get() );

	/** Stein 3 positionieren **/
	ref_ptr<PositionAttitudeTransform> stein3Scale = scaleObject( stein4OBJ.get(), Vec3( 2.0, 2.0, 2.0 ) );

	ref_ptr<MatrixTransform> steinpos3trans = translateObject( stein3Scale.get(), Vec3( -93.0, -85.0, 28.0 ) );

	gelaendeGrp->addChild( steinpos3trans.get() );

	/** Stein 4 positionieren **/
	ref_ptr<PositionAttitudeTransform> stein4Scale = scaleObject( stein3OBJ.get(), Vec3( 5.0, 5.0, 5.0 ) );

	ref_ptr<MatrixTransform> steinpos4trans = translateObject( stein4Scale.get(), Vec3( -20.0, -80.0, -3.0 ) );

	gelaendeGrp->addChild( steinpos4trans.get() );

	/**Stein 5 positionieren **/
	ref_ptr<PositionAttitudeTransform> stein5Scale = scaleObject( stein3OBJ.get(), Vec3( 3.0, 3.0, 3.0 ) );

	ref_ptr<MatrixTransform> steinpos5trans = translateObject( stein5Scale.get(), Vec3( 45.0, -60.0, -3.0 ) );

	gelaendeGrp->addChild( steinpos5trans.get() );

	/** Steingruppe positionieren **/
	ref_ptr<MatrixTransform> steinposgrp1trans = new MatrixTransform();
	steinposgrp1trans->setMatrix(Matrix::translate( Vec3( (18.0/4), -(65.0/4), -(9.5/4) ) ));
	steinposgrp1trans->addChild( stein1OBJ.get() );

	ref_ptr<MatrixTransform> steinposgrp2trans = new MatrixTransform();
	steinposgrp2trans->setMatrix(Matrix::translate( Vec3( (22.0/4), -(55.0/4), -(9.5/4) ) ));
	steinposgrp2trans->addChild( stein4OBJ.get() );

	ref_ptr<MatrixTransform> steinposgrp3trans = new MatrixTransform();
	steinposgrp3trans->setMatrix(Matrix::translate( Vec3( (16.0/4), -(60.0/4), -(9.5/4) ) ));
	steinposgrp3trans->addChild( stein2OBJ.get() );

	ref_ptr<MatrixTransform> steinposgrp4trans = new MatrixTransform();
	steinposgrp4trans->setMatrix(Matrix::translate( Vec3( (12.0/4), -(45.0/4), -(9.5/4) ) ));
	steinposgrp4trans->addChild( stein3OBJ.get() );

	ref_ptr<MatrixTransform> steingrpScale = new MatrixTransform();
	steingrpScale->setMatrix( Matrix::scale( Vec3( 4.0, 4.0, 4.0 ) ) );
	steingrpScale->addChild( steinposgrp1trans.get() );
	steingrpScale->addChild( steinposgrp2trans.get() );
	steingrpScale->addChild( steinposgrp3trans.get() );
	steingrpScale->addChild( steinposgrp4trans.get() );

	gelaendeGrp->addChild( steingrpScale.get() );
}

/** Setzen von Schilf **/
void Gelaende::schilfZusammenstellen( string* path, int detail )
{
	/** Pflanzen zu einer Gruppe setzen **/
	ref_ptr<PositionAttitudeTransform> schilf1Scale = scaleObject( schilfOBJ.get(), Vec3( 0.8, 0.8, 0.8 ) );
	ref_ptr<PositionAttitudeTransform> schilf2Scale = scaleObject( schilfOBJ.get(), Vec3( 1.1, 1.1, 1.1 ) );
	ref_ptr<PositionAttitudeTransform> schilf3Scale = scaleObject( schilfOBJ.get(), Vec3( 0.6, 0.6, 0.6 ) );

	ref_ptr<Group> schilfgrp = new Group();
	schilfgrp->addChild( translateObject( schilf1Scale.get(), Vec3( 0.0, 0.0, -0.2 ) ).get() );
	schilfgrp->addChild( translateObject( schilf2Scale.get(), Vec3( 0.8, 0.2, -0.2 ) ).get() );
	schilfgrp->addChild( translateObject( schilf1Scale.get(), Vec3( 0.4, 0.5, -0.2 ) ).get() );
	schilfgrp->addChild( translateObject( schilf1Scale.get(), Vec3( 0.0, 0.5, -0.2 ) ).get() );
	schilfgrp->addChild( translateObject( schilf1Scale.get(), Vec3( 1.5, 0.0, 0.0 ) ).get() );
	schilfgrp->addChild( translateObject( schilf3Scale.get(), Vec3( 0.4, -1.0, 0.0 ) ).get() );


	/** Oeffnen einer Datei mit Koordinaten **/
		const char *file;
		file=path->c_str();
		ifstream schilfkoord (file);

	if( !schilfkoord )
	{
		cerr << "Fehler beim Lesen der Schilf Koordinaten Datei." << endl;
		cerr << "Schilf kann nicht gesetzt werden." << endl;
	}
	else
	{
		/** Anzahl der Koordinaten einlesen **/
		string strZahl;
		stringstream Str;
		int menge;
		getline( schilfkoord, strZahl);
		Str << strZahl;
		Str >> menge;

		/** An jeder Koordinate eine Pflanzengruppe setzen **/
		for(int i = 0; i < menge; i++)
		{
			string strKoord;
			stringstream Str;

			float x, y, z;
			x = y = z = 0;
			getline( schilfkoord, strKoord );
			Str << strKoord;
			Str >> x;
			Str >> y;
			Str >> z;
			if(i%(10-detail)==0)
			{
				ref_ptr<OcclusionQueryNode> parent = new OcclusionQueryNode;
				parent->setVisibilityThreshold( 10 );
				parent->addChild( translateObject( schilfgrp.get(), Vec3( x, y, z ) ).get() );

				gelaendeGrp->addChild( parent.get() );
			}
		}
		/** Schliessen der Datei **/
		schilfkoord.close();
	}

}

/** Zurueckgeben des Objekts **/
ref_ptr<Group> Gelaende::getGelaende()
{
	return gelaendeGrp;
}

/** Hilfsmethode zum Skalieren eines Objektes **/
ref_ptr<PositionAttitudeTransform> Gelaende::scaleObject(ref_ptr<Node> node, Vec3 vector)
{
	ref_ptr<PositionAttitudeTransform> scale = new PositionAttitudeTransform;
	scale->addChild(node.get());
	scale->setScale(vector);
	return scale;
}

/** Hilfsmethode zum verschieben eines Objektes **/
ref_ptr<MatrixTransform> Gelaende::translateObject(ref_ptr<Group> group, Vec3 vector)
{
	ref_ptr<MatrixTransform> translate = new MatrixTransform();
	translate->addChild(group.get());
	translate->setMatrix(Matrix::translate(vector.x(), vector.y(), vector.z()));
	return translate;
}

/** Freigeben der Resourcen **/
Gelaende::~Gelaende()
{
	free(gelaendeOBJ);
	free(stein1OBJ);
	free(stein2OBJ);
	free(stein3OBJ);
	free(stein4OBJ);
	free(schilfOBJ);
	free(gelaendeGrp);

	gelaendeOBJ = stein1OBJ = NULL;
	stein2OBJ = stein3OBJ = NULL;
	stein4OBJ = schilfOBJ = gelaendeGrp = NULL;
}
